#include "board.h"

// Generate all cards in stock_pile
// Shuffle all cars

void board_init(struct board *board, struct args args) {
    memset(board, 0, sizeof(struct board));
    board->stock_pile = (card *)malloc(0);
    board->discard = (card *)malloc(0);
    board->dir = 1;
    board->next_player = NULL;  // waiting for draw
    for (int i = 0; i < args.deck_count; i++) {
        for (int j = 0; j < CARD_PER_DECK; j++) {
            board_push_card(board, (card){j, i});
        }
    }
}

// Clear discard & shuffle & append to stock_pile
void board_reshuffle(struct board *board) {
    while (board->stock_pile_count) {
        card c = board_pop_card(board);
        board_push_card(board, c);
    }
    while (board->discard_count) {
        if (board->discard_count > 1) {
            int choice = rand() % (board->discard_count - 1);
            card_swap(&(board->discard[board->discard_count - 1]), &(board->discard[choice]));
        }
        card c = board->discard[--board->discard_count];
        if (board->stock_pile_count % INIT_CARD_PILE_SIZE == 0)
            board->stock_pile = realloc(board->stock_pile, sizeof(card) * (size_t)(INIT_CARD_PILE_SIZE + board->stock_pile_count));
        board->stock_pile[board->stock_pile_count++] = c;
    }
    board->discard = realloc(board->discard, 0);
}

card board_pop_card(struct board *board) {
    if (!board->stock_pile_count) board_reshuffle(board);
    board->stock_pile_count--;
    card to_pop = board->stock_pile[board->stock_pile_count];
    if (board->stock_pile_count % INIT_CARD_PILE_SIZE == 0)
        board->stock_pile = realloc(board->stock_pile, sizeof(card) * (size_t)(INIT_CARD_PILE_SIZE + board->stock_pile_count));
    return to_pop;
}

void board_push_card(struct board *board, card c) {
    if (board->discard_count % INIT_CARD_PILE_SIZE == 0)
        board->discard = realloc(board->discard, sizeof(card) * (size_t)(INIT_CARD_PILE_SIZE + board->discard_count));
    board->discard[board->discard_count] = c;
    board->discard_count++;
    board->top_card = c;
}

void board_next_player(struct board *board) {
    if (card_is_rev(board->top_card)) board->dir = -board->dir;
    //     board->next_player = (board->next_player + board->dir + args.n) % args.n;
    //     if (card_is_skip(board->top_card)) board->next_player = (board->next_player + board->dir + args.n) % args.n;
    board->next_player = board->next_player->neighbour[(board->dir == 1) ? 1 : 0];
    if (card_is_skip(board->top_card)) board->next_player = board->next_player->neighbour[(board->dir == 1) ? 1 : 0];
}

void board_reset(struct board *board) {
    board->round_count++;
}

card board_top_card(struct board *board) {
    return board->discard[board->discard_count - 1];
}

bool board_can_play(struct board *board, card c) {
    card last_card = board->top_card;
    if (card_rank(c) == card_rank(last_card) || card_suit(c) == card_suit(last_card)) {
        if (!board->force_draw || card_is_special(c)) {
            return true;
        }
    }
    return false;
}

void board_destroy(struct board *board) {
    free(board->discard);
    free(board->stock_pile);
}
